<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="robots" content="noodp" />
        <title>JSON解析器实现 - L_B__</title><meta name="referrer" content="no-referrer">
<meta name="description" content="JSON解析器实现"><meta property="og:title" content="JSON解析器实现" />
<meta property="og:description" content="JSON解析器实现" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://acking-you.github.io/posts/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0/" /><meta property="og:image" content="https://acking-you.github.io/logo.png"/><meta property="article:section" content="posts" />
<meta property="article:published_time" content="2022-07-27T00:00:00+00:00" />
<meta property="article:modified_time" content="2022-07-27T00:00:00+00:00" />

<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="https://acking-you.github.io/logo.png"/>

<meta name="twitter:title" content="JSON解析器实现"/>
<meta name="twitter:description" content="JSON解析器实现"/>
<meta name="application-name" content="FeelIt">
<meta name="apple-mobile-web-app-title" content="FeelIt"><meta name="theme-color" content="#ffffff"><meta name="msapplication-TileColor" content="#da532c"><link rel="canonical" href="https://acking-you.github.io/posts/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0/" /><link rel="prev" href="https://acking-you.github.io/posts/logger%E6%97%A5%E5%BF%97%E5%BA%93%E7%9A%84%E5%AE%9E%E7%8E%B0/" /><link rel="next" href="https://acking-you.github.io/posts/c&#43;&#43;%E9%9D%A2%E8%AF%95%E4%B8%80%E6%9D%A1%E8%B7%AF/" /><link rel="stylesheet" href="/css/page.min.css"><link rel="stylesheet" href="/css/home.min.css"><script type="application/ld+json">
    {
        "@context": "http://schema.org",
        "@type": "BlogPosting",
        "headline": "JSON解析器实现",
        "inLanguage": "zh-CN",
        "mainEntityOfPage": {
            "@type": "WebPage",
            "@id": "https:\/\/acking-you.github.io\/posts\/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0\/"
        },"genre": "posts","keywords": "JSON解析器实现","wordcount":  3775 ,
        "url": "https:\/\/acking-you.github.io\/posts\/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0\/","datePublished": "2022-07-27T00:00:00+00:00","dateModified": "2022-07-27T00:00:00+00:00","publisher": {
            "@type": "Organization",
            "name": "作者"},"author": {
                "@type": "Person",
                "name": "作者"
            },"description": "JSON解析器实现"
    }
    </script></head><body data-header-desktop="auto" data-header-mobile="auto"><script>(window.localStorage && localStorage.getItem('theme') ? localStorage.getItem('theme') === 'dark' : ('auto' === 'auto' ? window.matchMedia('(prefers-color-scheme: dark)').matches : 'auto' === 'dark')) && document.body.setAttribute('theme', 'dark');</script>

        <div id="mask"></div><div class="wrapper"><header class="desktop" id="header-desktop">
    <div class="header-wrapper">
        <div class="header-title">
            <a href="/" title="L_B__">L_B__</a>
        </div>
        <div class="menu">
            <div class="menu-inner"><a class="menu-item" href="/posts/"> 文章 </a><a class="menu-item" href="/tags/"> 标签 </a><a class="menu-item" href="/categories/"> 分类 </a><span class="menu-item delimiter"></span><span class="menu-item search" id="search-desktop">
                        <input type="text" placeholder="搜索文章标题或内容..." id="search-input-desktop">
                        <a href="#" class="search-button search-toggle" id="search-toggle-desktop" title="搜索">
                            <i class="fas fa-search fa-fw"></i>
                        </a>
                        <a href="#" class="search-button search-clear" id="search-clear-desktop" title="清空">
                            <i class="fas fa-times-circle fa-fw"></i>
                        </a>
                        <span class="search-button search-loading" id="search-loading-desktop">
                            <i class="fas fa-spinner fa-fw fa-spin"></i>
                        </span>
                    </span><a href="javascript:void(0);" class="menu-item theme-switch" title="切换主题">
                    <i class="fas fa-adjust fa-fw"></i>
                </a>
            </div>
        </div>
    </div>
</header><header class="mobile" id="header-mobile">
    <div class="header-container">
        <div class="header-wrapper">
            <div class="header-title">
                <a href="/" title="L_B__">L_B__</a>
            </div>
            <div class="menu-toggle" id="menu-toggle-mobile">
                <span></span><span></span><span></span>
            </div>
        </div>
        <div class="menu" id="menu-mobile"><div class="search-wrapper">
                    <div class="search mobile" id="search-mobile">
                        <input type="text" placeholder="搜索文章标题或内容..." id="search-input-mobile">
                        <a href="#" class="search-button search-toggle" id="search-toggle-mobile" title="搜索">
                            <i class="fas fa-search fa-fw"></i>
                        </a>
                        <a href="#" class="search-button search-clear" id="search-clear-mobile" title="清空">
                            <i class="fas fa-times-circle fa-fw"></i>
                        </a>
                        <span class="search-button search-loading" id="search-loading-mobile">
                            <i class="fas fa-spinner fa-fw fa-spin"></i>
                        </span>
                    </div>
                    <a href="#" class="search-cancel" id="search-cancel-mobile">
                        取消
                    </a>
                </div><a class="menu-item" href="/posts/" title="">文章</a><a class="menu-item" href="/tags/" title="">标签</a><a class="menu-item" href="/categories/" title="">分类</a><div class="menu-item"><a href="javascript:void(0);" class="theme-switch" title="切换主题">
                    <i class="fas fa-adjust fa-fw"></i>
                </a>
            </div></div>
    </div>
</header><div class="search-dropdown desktop">
    <div id="search-dropdown-desktop"></div>
</div>
<div class="search-dropdown mobile">
    <div id="search-dropdown-mobile"></div>
</div><main class="main">
                <div class="container"><div class="toc" id="toc-auto">
            <h2 class="toc-title">目录</h2>
            <div class="toc-content" id="toc-content-auto"></div>
        </div><article class="page single" data-toc="disable"><div class="featured-image"><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://img-blog.csdnimg.cn/img_convert/c2804a2e21ea79a0b060126b82a9145c.png#pic_center"
        data-srcset="https://img-blog.csdnimg.cn/img_convert/c2804a2e21ea79a0b060126b82a9145c.png#pic_center, https://img-blog.csdnimg.cn/img_convert/c2804a2e21ea79a0b060126b82a9145c.png#pic_center 1.5x, https://img-blog.csdnimg.cn/img_convert/c2804a2e21ea79a0b060126b82a9145c.png#pic_center 2x"
        data-sizes="auto"
        alt="https://img-blog.csdnimg.cn/img_convert/c2804a2e21ea79a0b060126b82a9145c.png#pic_center"
        title="JSON解析器实现" /></div><div class="single-card" data-image="true"><h2 class="single-title animated flipInX">JSON解析器实现</h2><div class="post-meta">
                <div class="post-meta-line"><span class="post-author"><a href="/" title="Author" rel=" author" class="author"><i class="fas fa-user-circle fa-fw"></i>作者</a></span>&nbsp;<span class="post-category">出版于  <a href="/categories/%E4%B8%AA%E4%BA%BA%E8%BD%AE%E5%AD%90%E8%AE%A1%E5%88%92/"><i class="far fa-folder fa-fw"></i>个人轮子计划</a></span></div>
                <div class="post-meta-line"><span><i class="far fa-calendar-alt fa-fw"></i>&nbsp;<time datetime="2022-07-27">2022-07-27</time></span>&nbsp;<span><i class="fas fa-pencil-alt fa-fw"></i>&nbsp;约 3775 字</span>&nbsp;
                    <span><i class="far fa-clock fa-fw"></i>&nbsp;预计阅读 8 分钟</span>&nbsp;</div>
            </div>
            
            <hr><div class="details toc" id="toc-static"  data-kept="">
                    <div class="details-summary toc-title">
                        <span>目录</span>
                        <span><i class="details-icon fas fa-angle-right"></i></span>
                    </div>
                    <div class="details-content toc-content" id="toc-content-static"><nav id="TableOfContents">
  <ul>
    <li><a href="#json格式介绍">JSON格式介绍</a></li>
    <li><a href="#解析json字符串">解析json字符串</a>
      <ul>
        <li><a href="#创建jobject类">创建JObject类</a></li>
        <li><a href="#创建parser类">创建Parser类</a></li>
      </ul>
    </li>
    <li><a href="#完善jobject类">完善JObject类</a>
      <ul>
        <li><a href="#初始化接口">初始化接口</a></li>
        <li><a href="#请求值接口">请求值接口</a></li>
        <li><a href="#重载方法让对象更好用">重载方法让对象更好用</a></li>
      </ul>
    </li>
    <li><a href="#完善parser类">完善Parser类</a></li>
    <li><a href="#完成序列化和反序列化过程">完成序列化和反序列化过程</a>
      <ul>
        <li><a href="#序列化接口设计">序列化接口设计</a></li>
      </ul>
    </li>
    <li><a href="#简单使用">简单使用</a></li>
  </ul>
</nav></div>
                </div><div class="content" id="content"><blockquote>
<p>代码开源仓库：<a href="https://github.com/ACking-you/MyUtil/tree/master/json-parser" target="_blank" rel="noopener noreffer">cpp造轮子项目&ndash;实现json解析器</a></p>
</blockquote>
<h2 id="json格式介绍">JSON格式介绍</h2>
<p>JSON(<a href="https://baike.baidu.com/item/JavaScript" target="_blank" rel="noopener noreffer">JavaScript</a> Object Notation)，是一种序列化的格式，最大的优点在于可读性极强，以及可直接嵌入到js代码中，所以广泛运用于web数据的收发。</p>
<p>JSON格式有以下基本类型：</p>
<ul>
<li>
<p>null类型：值为null，表示为空</p>
</li>
<li>
<p>bool类型：值为true和false</p>
</li>
<li>
<p>number类型：值为int、double（即整数或小数</p>
</li>
<li>
<p>string类型：形如 &ldquo;abc&rdquo;</p>
</li>
</ul>
<p>以及以下复合类型：</p>
<ul>
<li>list类型（也称array类型）</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="p">[</span><span class="s2">&#34;abc&#34;</span><span class="p">,</span><span class="mf">3.2</span><span class="p">,</span><span class="mi">323</span><span class="p">,</span><span class="s2">&#34;sdaf&#34;</span><span class="p">]</span>
</code></pre></div><ul>
<li>dict类型（也称object类型）</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="p">{</span>
    <span class="nt">&#34;id&#34;</span><span class="p">:</span><span class="mi">32</span><span class="p">,</span>
    <span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;hhh&#34;</span>
<span class="p">}</span>
</code></pre></div><h2 id="解析json字符串">解析json字符串</h2>
<p>整套解析流程如下：</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/231baf4270a64bf6aa38ca5961507611~tplv-k3u1fbpfcp-watermark.image?"
        data-srcset="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/231baf4270a64bf6aa38ca5961507611~tplv-k3u1fbpfcp-watermark.image?, https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/231baf4270a64bf6aa38ca5961507611~tplv-k3u1fbpfcp-watermark.image? 1.5x, https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/231baf4270a64bf6aa38ca5961507611~tplv-k3u1fbpfcp-watermark.image? 2x"
        data-sizes="auto"
        alt="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/231baf4270a64bf6aa38ca5961507611~tplv-k3u1fbpfcp-watermark.image?"
        title="绘图1.png" /></p>
<h3 id="创建jobject类">创建JObject类</h3>
<p>我们需要把json的类型对应到计算机语言的类型。</p>
<p>由于json的数据在我们看来都是字符串，那么有如下对应关系：</p>
<ul>
<li>&ldquo;null&quot;对应我们构造的null类型</li>
<li>“true&rdquo;,&ldquo;false&quot;对应内部的bool类型即可</li>
<li>number类型数据对应int、double类型</li>
<li>string类型数据对应string即可</li>
<li>list类型对应C++中的vector</li>
<li>dict类型对应C++中的map或unordered_map</li>
</ul>
<p>我们在计算机语言中，需要构造一个对象类型，用于将以上类型全部涵盖。</p>
<p>在C++中我们通过std::variant来进行，还需要一个枚举tag来表示当前对象内存储的数据类型。</p>
<p>当然如果做的更绝的话，可以通过一个void* + 申请堆内存来解决，然后再强转为对应类型来操作。</p>
<p>对应的代码如下：（中间的类方法就暂时省略了</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp">   
<span class="k">enum</span> <span class="nc">TYPE</span>
<span class="p">{</span>
    <span class="n">T_NULL</span><span class="p">,</span>
    <span class="n">T_BOOL</span><span class="p">,</span>
    <span class="n">T_INT</span><span class="p">,</span>
    <span class="n">T_DOUBLE</span><span class="p">,</span>
    <span class="n">T_STR</span><span class="p">,</span>
    <span class="n">T_LIST</span><span class="p">,</span>
    <span class="n">T_DICT</span>
<span class="p">};</span>

<span class="k">using</span> <span class="n">null_t</span> <span class="o">=</span> <span class="n">string</span><span class="p">;</span>
<span class="k">using</span> <span class="n">int_t</span> <span class="o">=</span> <span class="kt">int32_t</span><span class="p">;</span>
<span class="k">using</span> <span class="n">bool_t</span> <span class="o">=</span> <span class="kt">bool</span><span class="p">;</span>
<span class="k">using</span> <span class="n">double_t</span> <span class="o">=</span> <span class="kt">double</span><span class="p">;</span>
<span class="k">using</span> <span class="n">str_t</span> <span class="o">=</span> <span class="n">string</span><span class="p">;</span>
<span class="k">using</span> <span class="n">list_t</span> <span class="o">=</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">JObject</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">using</span> <span class="n">dict_t</span> <span class="o">=</span> <span class="n">map</span><span class="o">&lt;</span><span class="n">string</span><span class="p">,</span> <span class="n">JObject</span><span class="o">&gt;</span><span class="p">;</span>

<span class="k">class</span> <span class="nc">JObject</span>
<span class="p">{</span>
<span class="k">public</span><span class="o">:</span>
    <span class="k">using</span> <span class="n">value_t</span> <span class="o">=</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">bool_t</span><span class="p">,</span> <span class="n">int_t</span><span class="p">,</span> <span class="n">double_t</span><span class="p">,</span> <span class="n">str_t</span><span class="p">,</span> <span class="n">list_t</span><span class="p">,</span> <span class="n">dict_t</span><span class="o">&gt;</span><span class="p">;</span>
    <span class="p">...</span>
<span class="k">private</span><span class="o">:</span>
    <span class="n">TYPE</span> <span class="n">m_type</span><span class="p">;</span>
    <span class="n">value_t</span> <span class="n">m_value</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div><h3 id="创建parser类">创建Parser类</h3>
<p>我们有了JObject，可以把所有的JSON数据接收起来，现在要做的就是扫描JSON字符串，对其中的数据进行读取处理，然后转化为JObject。</p>
<p>关键代码如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="n">JObject</span> <span class="n">Parser</span><span class="o">::</span><span class="n">parse</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">char</span> <span class="n">token</span> <span class="o">=</span> <span class="n">get_next_token</span><span class="p">();</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">token</span> <span class="o">==</span> <span class="sc">&#39;n&#39;</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">parse_null</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">token</span> <span class="o">==</span> <span class="sc">&#39;t&#39;</span> <span class="o">||</span> <span class="n">token</span> <span class="o">==</span> <span class="sc">&#39;f&#39;</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">parse_bool</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">token</span> <span class="o">==</span> <span class="sc">&#39;-&#39;</span> <span class="o">||</span> <span class="n">std</span><span class="o">::</span><span class="n">isdigit</span><span class="p">(</span><span class="n">token</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">parse_number</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">token</span> <span class="o">==</span> <span class="sc">&#39;\&#34;&#39;</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">parse_string</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">token</span> <span class="o">==</span> <span class="sc">&#39;[&#39;</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">parse_list</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">token</span> <span class="o">==</span> <span class="sc">&#39;{&#39;</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">parse_dict</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">logic_error</span><span class="p">(</span><span class="s">&#34;unexpected character in parse json&#34;</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div><blockquote>
<p>以上就是整个字符串的解析过程，每次通过get_next_token这个方法得到整个字符串的下一个token，根据token决定解析对应的数据类型。</p>
</blockquote>
<h4 id="get_next_token方法">get_next_token方法</h4>
<p>跳过空白符号，以及跳过注释（标准的JSON格式不支持注释，我这里硬加的，为了vscode的JSON格式配置文件解析</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="kt">char</span> <span class="n">Parser</span><span class="o">::</span><span class="n">get_next_token</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">isspace</span><span class="p">(</span><span class="n">m_str</span><span class="p">[</span><span class="n">m_idx</span><span class="p">]))</span> <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">m_idx</span> <span class="o">&gt;=</span> <span class="n">m_str</span><span class="p">.</span><span class="n">size</span><span class="p">())</span>
        <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">logic_error</span><span class="p">(</span><span class="s">&#34;unexpected character in parse json&#34;</span><span class="p">);</span>
    <span class="c1">//如果是注释，记得跳过
</span><span class="c1"></span>    <span class="n">skip_comment</span><span class="p">();</span>
    <span class="k">return</span> <span class="n">m_str</span><span class="p">[</span><span class="n">m_idx</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div><h4 id="parse_null和parse_bool">parse_null和parse_bool</h4>
<p>由于这两个很简单，就放在一起了。</p>
<ul>
<li>parse_null</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="n">JObject</span> <span class="n">Parser</span><span class="o">::</span><span class="n">parse_null</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">m_str</span><span class="p">.</span><span class="n">compare</span><span class="p">(</span><span class="n">m_idx</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="s">&#34;null&#34;</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">m_idx</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
        <span class="k">return</span> <span class="p">{};</span>
    <span class="p">}</span>
    <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">logic_error</span><span class="p">(</span><span class="s">&#34;parse null error&#34;</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div><ul>
<li>parse_bool</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="kt">bool</span> <span class="n">Parser</span><span class="o">::</span><span class="n">parse_bool</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">m_str</span><span class="p">.</span><span class="n">compare</span><span class="p">(</span><span class="n">m_idx</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="s">&#34;true&#34;</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">m_idx</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
        <span class="k">return</span> <span class="s">&#34;true&#34;</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">m_str</span><span class="p">.</span><span class="n">compare</span><span class="p">(</span><span class="n">m_idx</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="s">&#34;false&#34;</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">m_idx</span> <span class="o">+=</span> <span class="mi">5</span><span class="p">;</span>
        <span class="k">return</span> <span class="s">&#34;false&#34;</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">logic_error</span><span class="p">(</span><span class="s">&#34;parse bool error&#34;</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div><h4 id="parse_number">parse_number</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="n">JObject</span> <span class="n">Parser</span><span class="o">::</span><span class="n">parse_number</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">auto</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">m_idx</span><span class="p">;</span>
    <span class="c1">//integer part
</span><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="n">m_str</span><span class="p">[</span><span class="n">m_idx</span><span class="p">]</span> <span class="o">==</span> <span class="sc">&#39;-&#39;</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">isdigit</span><span class="p">(</span><span class="n">m_str</span><span class="p">[</span><span class="n">m_idx</span><span class="p">]))</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">isdigit</span><span class="p">(</span><span class="n">m_str</span><span class="p">[</span><span class="n">m_idx</span><span class="p">]))</span>
            <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
    <span class="k">else</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">logic_error</span><span class="p">(</span><span class="s">&#34;invalid character in number&#34;</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">m_str</span><span class="p">[</span><span class="n">m_idx</span><span class="p">]</span> <span class="o">!=</span> <span class="sc">&#39;.&#39;</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="n">strtol</span><span class="p">(</span><span class="n">m_str</span><span class="p">.</span><span class="n">c_str</span><span class="p">()</span> <span class="o">+</span> <span class="n">pos</span><span class="p">,</span> <span class="k">nullptr</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="c1">//decimal part
</span><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="n">m_str</span><span class="p">[</span><span class="n">m_idx</span><span class="p">]</span> <span class="o">==</span> <span class="sc">&#39;.&#39;</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">std</span><span class="o">::</span><span class="n">isdigit</span><span class="p">(</span><span class="n">m_str</span><span class="p">[</span><span class="n">m_idx</span><span class="p">]))</span>
        <span class="p">{</span>
            <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">logic_error</span><span class="p">(</span><span class="s">&#34;at least one digit required in parse float part!&#34;</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">isdigit</span><span class="p">(</span><span class="n">m_str</span><span class="p">[</span><span class="n">m_idx</span><span class="p">]))</span>
            <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nf">strtof64</span><span class="p">(</span><span class="n">m_str</span><span class="p">.</span><span class="n">c_str</span><span class="p">()</span> <span class="o">+</span> <span class="n">pos</span><span class="p">,</span> <span class="k">nullptr</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div><h4 id="parse_list">parse_list</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="n">JObject</span> <span class="n">Parser</span><span class="o">::</span><span class="n">parse_list</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">JObject</span> <span class="nf">arr</span><span class="p">((</span><span class="n">list_t</span><span class="p">()));</span><span class="c1">//得到list类型的JObject
</span><span class="c1"></span>    <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
    <span class="kt">char</span> <span class="n">ch</span> <span class="o">=</span> <span class="n">get_next_token</span><span class="p">();</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">ch</span> <span class="o">==</span> <span class="sc">&#39;]&#39;</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">arr</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">while</span> <span class="p">(</span><span class="nb">true</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">arr</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">parse</span><span class="p">());</span>
        <span class="n">ch</span> <span class="o">=</span> <span class="n">get_next_token</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">ch</span> <span class="o">==</span> <span class="sc">&#39;]&#39;</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">ch</span> <span class="o">!=</span> <span class="sc">&#39;,&#39;</span><span class="p">)</span> <span class="c1">//如果不是逗号
</span><span class="c1"></span>        <span class="p">{</span>
            <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">logic_error</span><span class="p">(</span><span class="s">&#34;expected &#39;,&#39; in parse list&#34;</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="c1">//跳过逗号
</span><span class="c1"></span>        <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">arr</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><h4 id="parse_dict">parse_dict</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="n">JObject</span> <span class="n">Parser</span><span class="o">::</span><span class="n">parse_dict</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">JObject</span> <span class="nf">dict</span><span class="p">((</span><span class="n">dict_t</span><span class="p">()));</span><span class="c1">//得到dict类型的JObject
</span><span class="c1"></span>    <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
    <span class="kt">char</span> <span class="n">ch</span> <span class="o">=</span> <span class="n">get_next_token</span><span class="p">();</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">ch</span> <span class="o">==</span> <span class="sc">&#39;}&#39;</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">dict</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">while</span> <span class="p">(</span><span class="nb">true</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">//解析key
</span><span class="c1"></span>        <span class="n">string</span> <span class="n">key</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">parse</span><span class="p">().</span><span class="n">Value</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span><span class="p">());</span>
        <span class="n">ch</span> <span class="o">=</span> <span class="n">get_next_token</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">ch</span> <span class="o">!=</span> <span class="sc">&#39;:&#39;</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">logic_error</span><span class="p">(</span><span class="s">&#34;expected &#39;:&#39; in parse dict&#34;</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>

        <span class="c1">//解析value
</span><span class="c1"></span>        <span class="n">dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">parse</span><span class="p">();</span>
        <span class="n">ch</span> <span class="o">=</span> <span class="n">get_next_token</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">ch</span> <span class="o">==</span> <span class="sc">&#39;}&#39;</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span> <span class="c1">//解析完毕
</span><span class="c1"></span>        <span class="p">}</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">ch</span> <span class="o">!=</span> <span class="sc">&#39;,&#39;</span><span class="p">)</span><span class="c1">//没有结束，此时必须为逗号
</span><span class="c1"></span>        <span class="p">{</span>
            <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">logic_error</span><span class="p">(</span><span class="s">&#34;expected &#39;,&#39; in parse dict&#34;</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="c1">//跳过逗号
</span><span class="c1"></span>        <span class="n">m_idx</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">dict</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><h2 id="完善jobject类">完善JObject类</h2>
<p>很明显，我们需要为JObject类提供一个方法，此方法可以让调用者直接访问到std::variant里面对应的数据，并且我们也需要提供一个方法能让JObject快速初始化为对应的类型。</p>
<h3 id="初始化接口">初始化接口</h3>
<blockquote>
<p>添加好下面这些方法后，外界可通过调用方法把JObject的内部状态改变。</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="kt">void</span> <span class="nf">Null</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">m_type</span> <span class="o">=</span> <span class="n">T_NULL</span><span class="p">;</span>
    <span class="n">m_value</span> <span class="o">=</span> <span class="s">&#34;null&#34;</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">Int</span><span class="p">(</span><span class="n">int_t</span> <span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">m_value</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
    <span class="n">m_type</span> <span class="o">=</span> <span class="n">T_INT</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">Bool</span><span class="p">(</span><span class="n">bool_t</span> <span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">m_value</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
    <span class="n">m_type</span> <span class="o">=</span> <span class="n">T_BOOL</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">Double</span><span class="p">(</span><span class="n">double_t</span> <span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">m_type</span> <span class="o">=</span> <span class="n">T_DOUBLE</span><span class="p">;</span>
    <span class="n">m_value</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">Str</span><span class="p">(</span><span class="n">string_view</span> <span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">m_value</span> <span class="o">=</span> <span class="n">string</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
    <span class="n">m_type</span> <span class="o">=</span> <span class="n">T_STR</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">List</span><span class="p">(</span><span class="n">list_t</span> <span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">m_value</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
    <span class="n">m_type</span> <span class="o">=</span> <span class="n">T_LIST</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">Dict</span><span class="p">(</span><span class="n">dict_t</span> <span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">m_value</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
    <span class="n">m_type</span> <span class="o">=</span> <span class="n">T_DICT</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><blockquote>
<p>为了方便平时的赋值时候的隐式转化，我们应该再添加对应的构造函数，如下：（隐式转化在C++里有个坑，只能为类提供一种方向的隐式转化，比如提供了int把转为JObject的隐式转化后，就不能再提供把JObject转为int的隐式转化了，这两种必须要有一个是explicit，否则报错</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="n">JObject</span><span class="p">()</span><span class="c1">//默认为null类型
</span><span class="c1"></span><span class="p">{</span>
    <span class="n">m_type</span> <span class="o">=</span> <span class="n">T_NULL</span><span class="p">;</span>
    <span class="n">m_value</span> <span class="o">=</span> <span class="s">&#34;null&#34;</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">JObject</span><span class="p">(</span><span class="n">int_t</span> <span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">Int</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">JObject</span><span class="p">(</span><span class="n">bool_t</span> <span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">Bool</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">JObject</span><span class="p">(</span><span class="n">double_t</span> <span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">Double</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">JObject</span><span class="p">(</span><span class="n">str_t</span> <span class="k">const</span> <span class="o">&amp;</span><span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">Str</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">JObject</span><span class="p">(</span><span class="n">list_t</span> <span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">List</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">value</span><span class="p">));</span>
<span class="p">}</span>

<span class="n">JObject</span><span class="p">(</span><span class="n">dict_t</span> <span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">Dict</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">value</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div><h3 id="请求值接口">请求值接口</h3>
<p>设计思路：本人不喜欢一大堆的get/set，那样真的是麻烦。我通过提供一个Value方法，该方法为泛型，其内部有调用value()方法得到对应的数据指针，而Value方法则负责将指针强转，其内部也实现了强大的错误处理，防止处理指针的意外宕机。。。</p>
<blockquote>
<p>value方法如下，用于调用get_if得到对应的数据指针，关于怎么获取std::variant的数据，有get和get_if两种方式，get得到的是对象的引用，如果获取不到，则抛出异常，get_if获取对象的指针，如果获取不到则返回nullptr。我选择使用get_if的原因是，这个异常的处理可以由你自己来设定提示，而不是对着底层的get提示而摸不着头脑。</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="kt">void</span> <span class="o">*</span><span class="n">JObject</span><span class="o">::</span><span class="n">value</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">switch</span> <span class="p">(</span><span class="n">m_type</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">case</span> <span class="nl">T_NULL</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">get_if</span><span class="o">&lt;</span><span class="n">str_t</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="n">m_value</span><span class="p">);</span>
        <span class="k">case</span> <span class="nl">T_BOOL</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">get_if</span><span class="o">&lt;</span><span class="n">bool_t</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="n">m_value</span><span class="p">);</span>
        <span class="k">case</span> <span class="nl">T_INT</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">get_if</span><span class="o">&lt;</span><span class="n">int_t</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="n">m_value</span><span class="p">);</span>
        <span class="k">case</span> <span class="nl">T_DOUBLE</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">get_if</span><span class="o">&lt;</span><span class="n">double_t</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="n">m_value</span><span class="p">);</span>
        <span class="k">case</span> <span class="nl">T_LIST</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">get_if</span><span class="o">&lt;</span><span class="n">list_t</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="n">m_value</span><span class="p">);</span>
        <span class="k">case</span> <span class="nl">T_DICT</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">get_if</span><span class="o">&lt;</span><span class="n">dict_t</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="n">m_value</span><span class="p">);</span>
        <span class="k">case</span> <span class="nl">T_STR</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">get_if</span><span class="o">&lt;</span><span class="n">str_t</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="n">m_value</span><span class="p">);</span>
        <span class="k">default</span><span class="o">:</span>
            <span class="k">return</span> <span class="k">nullptr</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div><blockquote>
<p>Value方法：</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="cp">#define THROW_GET_ERROR(erron) throw std::logic_error(&#34;type error in get &#34;#erron&#34; value!&#34;)
</span><span class="cp"></span>
<span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">V</span><span class="o">&gt;</span>
    <span class="n">V</span> <span class="o">&amp;</span><span class="n">Value</span><span class="p">()</span>
<span class="p">{</span>
    <span class="c1">//添加安全检查
</span><span class="c1"></span>    <span class="k">if</span> <span class="nf">constexpr</span><span class="p">(</span><span class="n">IS_TYPE</span><span class="p">(</span><span class="n">V</span><span class="p">,</span> <span class="n">str_t</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">m_type</span> <span class="o">!=</span> <span class="n">T_STR</span><span class="p">)</span>
            <span class="n">THROW_GET_ERROR</span><span class="p">(</span><span class="n">string</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nf">constexpr</span><span class="p">(</span><span class="n">IS_TYPE</span><span class="p">(</span><span class="n">V</span><span class="p">,</span> <span class="n">bool_t</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">m_type</span> <span class="o">!=</span> <span class="n">T_BOOL</span><span class="p">)</span>
            <span class="n">THROW_GET_ERROR</span><span class="p">(</span><span class="n">BOOL</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nf">constexpr</span><span class="p">(</span><span class="n">IS_TYPE</span><span class="p">(</span><span class="n">V</span><span class="p">,</span> <span class="n">int_t</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">m_type</span> <span class="o">!=</span> <span class="n">T_INT</span><span class="p">)</span>
            <span class="n">THROW_GET_ERROR</span><span class="p">(</span><span class="n">INT</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nf">constexpr</span><span class="p">(</span><span class="n">IS_TYPE</span><span class="p">(</span><span class="n">V</span><span class="p">,</span> <span class="n">double_t</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">m_type</span> <span class="o">!=</span> <span class="n">T_DOUBLE</span><span class="p">)</span>
            <span class="n">THROW_GET_ERROR</span><span class="p">(</span><span class="n">DOUBLE</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nf">constexpr</span><span class="p">(</span><span class="n">IS_TYPE</span><span class="p">(</span><span class="n">V</span><span class="p">,</span> <span class="n">list_t</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">m_type</span> <span class="o">!=</span> <span class="n">T_LIST</span><span class="p">)</span>
            <span class="n">THROW_GET_ERROR</span><span class="p">(</span><span class="n">LIST</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nf">constexpr</span><span class="p">(</span><span class="n">IS_TYPE</span><span class="p">(</span><span class="n">V</span><span class="p">,</span> <span class="n">dict_t</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">m_type</span> <span class="o">!=</span> <span class="n">T_DICT</span><span class="p">)</span>
            <span class="n">THROW_GET_ERROR</span><span class="p">(</span><span class="n">DICT</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="o">*</span><span class="n">v</span> <span class="o">=</span> <span class="n">value</span><span class="p">();</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">v</span> <span class="o">==</span> <span class="k">nullptr</span><span class="p">)</span>
        <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">logic_error</span><span class="p">(</span><span class="s">&#34;unknown type in JObject::Value()&#34;</span><span class="p">);</span>
    <span class="k">return</span> <span class="o">*</span><span class="p">((</span><span class="n">V</span> <span class="o">*</span><span class="p">)</span> <span class="n">v</span><span class="p">);</span> <span class="c1">//强转即可
</span><span class="c1"></span><span class="p">}</span>
</code></pre></div><h3 id="重载方法让对象更好用">重载方法让对象更好用</h3>
<p>当JObject为dict类型时，我们可以直接用下标运算符进行key-value的赋值（得益于隐式转化和运算符重载</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="n">JObject</span> <span class="o">&amp;</span><span class="k">operator</span><span class="p">[](</span><span class="n">string</span> <span class="k">const</span> <span class="o">&amp;</span><span class="n">key</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">m_type</span> <span class="o">==</span> <span class="n">T_DICT</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">auto</span> <span class="o">&amp;</span><span class="n">dict</span> <span class="o">=</span> <span class="n">Value</span><span class="o">&lt;</span><span class="n">dict_t</span><span class="o">&gt;</span><span class="p">();</span>
        <span class="k">return</span> <span class="n">dict</span><span class="p">[</span><span class="n">key</span><span class="p">];</span>
    <span class="p">}</span>
    <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">logic_error</span><span class="p">(</span><span class="s">&#34;not dict type! JObject::opertor[]()&#34;</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div><p>同样如果为list对象，我们也准备了push_back等方法</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="kt">void</span> <span class="nf">push_back</span><span class="p">(</span><span class="n">JObject</span> <span class="n">item</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">m_type</span> <span class="o">==</span> <span class="n">T_LIST</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">auto</span> <span class="o">&amp;</span><span class="n">list</span> <span class="o">=</span> <span class="n">Value</span><span class="o">&lt;</span><span class="n">list_t</span><span class="o">&gt;</span><span class="p">();</span>
        <span class="n">list</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">item</span><span class="p">));</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">logic_error</span><span class="p">(</span><span class="s">&#34;not a list type! JObjcct::push_back()&#34;</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div><p>当然，为了让类更好用，你也可以重载很多其他方法，但是注意别忘了类型的安全检查！</p>
<h2 id="完善parser类">完善Parser类</h2>
<p>我们之前是完成了整个字符串到JObject的解析过程，但是每次都需要创建一个Parser类，然后调用方法，这样的过程未免有些繁琐，我们可以对外提供FromString的静态方法，然后充分利用一个对象便可完成整个解析过程。</p>
<p>如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="n">JObject</span> <span class="n">Parser</span><span class="o">::</span><span class="n">FromString</span><span class="p">(</span><span class="n">string_view</span> <span class="n">content</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">static</span> <span class="n">Parser</span> <span class="n">instance</span><span class="p">;</span>
    <span class="n">instance</span><span class="p">.</span><span class="n">init</span><span class="p">(</span><span class="n">content</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">instance</span><span class="p">.</span><span class="n">parse</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div><h2 id="完成序列化和反序列化过程">完成序列化和反序列化过程</h2>
<p>我们前面所做的工作其实已经把这个过程相当于完成了，当然还差一个把JObject变为JSON字符串的方法，现在添加上就是，也不是很难，按照相似的逻辑反推一遍就行。如下给JObject添加一个to_string方法：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="n">string</span> <span class="n">JObject</span><span class="o">::</span><span class="n">to_string</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">void</span> <span class="o">*</span><span class="n">value</span> <span class="o">=</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">value</span><span class="p">();</span>
    <span class="n">std</span><span class="o">::</span><span class="n">ostringstream</span> <span class="n">os</span><span class="p">;</span>
    <span class="k">switch</span> <span class="p">(</span><span class="n">m_type</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">case</span> <span class="nl">T_NULL</span><span class="p">:</span>
            <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;null&#34;</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="nl">T_BOOL</span><span class="p">:</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">GET_VALUE</span><span class="p">(</span><span class="kt">bool</span><span class="p">))</span>
                <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;true&#34;</span><span class="p">;</span>
            <span class="k">else</span> <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;false&#34;</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="nl">T_INT</span><span class="p">:</span>
            <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="n">GET_VALUE</span><span class="p">(</span><span class="kt">int</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="nl">T_DOUBLE</span><span class="p">:</span>
            <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="n">GET_VALUE</span><span class="p">(</span><span class="kt">double</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="nl">T_STR</span><span class="p">:</span>
            <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\&#34;&#39;</span> <span class="o">&lt;&lt;</span> <span class="n">GET_VALUE</span><span class="p">(</span><span class="n">string</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\&#34;&#39;</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="nl">T_LIST</span><span class="p">:</span>
        <span class="p">{</span>
            <span class="n">list_t</span> <span class="o">&amp;</span><span class="n">list</span> <span class="o">=</span> <span class="n">GET_VALUE</span><span class="p">(</span><span class="n">list_t</span><span class="p">);</span>
            <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;[&#39;</span><span class="p">;</span>
            <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">list</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">!=</span> <span class="n">list</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">list</span><span class="p">[</span><span class="n">i</span><span class="p">]).</span><span class="n">to_string</span><span class="p">());</span>
                    <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;,&#39;</span><span class="p">;</span>
                <span class="p">}</span> <span class="k">else</span> <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">list</span><span class="p">[</span><span class="n">i</span><span class="p">]).</span><span class="n">to_string</span><span class="p">());</span>
            <span class="p">}</span>
            <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;]&#39;</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">case</span> <span class="nl">T_DICT</span><span class="p">:</span>
        <span class="p">{</span>
            <span class="n">dict_t</span> <span class="o">&amp;</span><span class="n">dict</span> <span class="o">=</span> <span class="n">GET_VALUE</span><span class="p">(</span><span class="n">dict_t</span><span class="p">);</span>
            <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;{&#39;</span><span class="p">;</span>
            <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">dict</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">dict</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="o">++</span><span class="n">it</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">it</span> <span class="o">!=</span> <span class="n">dict</span><span class="p">.</span><span class="n">begin</span><span class="p">())</span> <span class="c1">//为了保证最后的json格式正确
</span><span class="c1"></span>                    <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;,&#39;</span><span class="p">;</span>
                <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\&#34;&#39;</span> <span class="o">&lt;&lt;</span> <span class="n">it</span><span class="o">-&gt;</span><span class="n">first</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\&#34;</span><span class="s">:&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">it</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">.</span><span class="n">to_string</span><span class="p">();</span>
            <span class="p">}</span>
            <span class="n">os</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;}&#39;</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">default</span><span class="o">:</span>
            <span class="k">return</span> <span class="s">&#34;&#34;</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">os</span><span class="p">.</span><span class="n">str</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div><p>有关JObject的方法也都补充的差不多了，那么我们现在要考虑的是如何通过JObject这个中间对象将我们自定义的任何一个类给序列化和反序列化？</p>
<p>如图：</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/231baf4270a64bf6aa38ca5961507611~tplv-k3u1fbpfcp-watermark.image?"
        data-srcset="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/231baf4270a64bf6aa38ca5961507611~tplv-k3u1fbpfcp-watermark.image?, https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/231baf4270a64bf6aa38ca5961507611~tplv-k3u1fbpfcp-watermark.image? 1.5x, https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/231baf4270a64bf6aa38ca5961507611~tplv-k3u1fbpfcp-watermark.image? 2x"
        data-sizes="auto"
        alt="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/231baf4270a64bf6aa38ca5961507611~tplv-k3u1fbpfcp-watermark.image?"
        title="绘图1.png" /></p>
<p>所有的序列化和反序列化的过程都依托于JObject进行。而Parser这个类在中间作为一个方便使用的对外接口。</p>
<h3 id="序列化接口设计">序列化接口设计</h3>
<p>在Parser类中添加一个ToJSON的静态方法，用来对任意类型进行序列化，这个方法使用模板。</p>
<p>代码如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">T</span><span class="o">&gt;</span>
    <span class="k">static</span> <span class="n">string</span> <span class="n">ToJSON</span><span class="p">(</span><span class="n">T</span> <span class="k">const</span> <span class="o">&amp;</span><span class="n">src</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">//如果是基本类型
</span><span class="c1"></span>    <span class="k">if</span> <span class="nf">constexpr</span><span class="p">(</span><span class="n">IS_TYPE</span><span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="n">int_t</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="n">JObject</span> <span class="n">object</span><span class="p">(</span><span class="n">src</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">object</span><span class="p">.</span><span class="n">to_string</span><span class="p">();</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nf">constexpr</span><span class="p">(</span><span class="n">IS_TYPE</span><span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="n">bool_t</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="n">JObject</span> <span class="n">object</span><span class="p">(</span><span class="n">src</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">object</span><span class="p">.</span><span class="n">to_string</span><span class="p">();</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nf">constexpr</span><span class="p">(</span><span class="n">IS_TYPE</span><span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="n">double_t</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="n">JObject</span> <span class="n">object</span><span class="p">(</span><span class="n">src</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">object</span><span class="p">.</span><span class="n">to_string</span><span class="p">();</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nf">constexpr</span><span class="p">(</span><span class="n">IS_TYPE</span><span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="n">str_t</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="n">JObject</span> <span class="n">object</span><span class="p">(</span><span class="n">src</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">object</span><span class="p">.</span><span class="n">to_string</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="c1">//如果是自定义类型调用方法完成dict的赋值，然后to_string即可
</span><span class="c1"></span>    <span class="n">json</span><span class="o">::</span><span class="n">JObject</span> <span class="n">obj</span><span class="p">((</span><span class="n">json</span><span class="o">::</span><span class="n">dict_t</span><span class="p">()));</span>
    <span class="n">src</span><span class="p">.</span><span class="n">FUNC_TO_NAME</span><span class="p">(</span><span class="n">obj</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">obj</span><span class="p">.</span><span class="n">to_string</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div><blockquote>
<p>如上代码如果是基本类型则直接初始化JObject调用to_string方法，如果是自定义类型，则需要在该类型中嵌入一个方法，这个方法名字我们用FUNC_TO_NAME这个宏代替。</p>
</blockquote>
<p>也就是说，如果是自定义的类型，那么肯定就是对应JSON数据的dict类型，所以只需要你对该类型定义对应的方法，该方法需要将值传递给JObject，为了简化这个过程我们用宏来替代。</p>
<p>宏定义如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="cp">#define FUNC_TO_NAME _to_json
</span><span class="cp">#define FUNC_FROM_NAME _from_json
</span><span class="cp"></span>
<span class="cp">#define START_TO_JSON void FUNC_TO_NAME(json::JObject &amp; obj) const{
</span><span class="cp">#define to(key) obj[key]
</span><span class="cp"></span>    <span class="c1">//push一个自定义类型的成员
</span><span class="c1"></span><span class="cp">#define to_struct(key, struct_member) json::JObject tmp((json::dict_t())); struct_member.FUNC_TO_NAME(tmp); obj[key] = tmp
</span><span class="cp">#define END_TO_JSON  }
</span><span class="cp"></span>
<span class="cp">#define START_FROM_JSON void FUNC_FROM_NAME(json::JObject&amp; obj) {
</span><span class="cp">#define from(key, type) obj[key].Value&lt;type&gt;()
</span><span class="cp">#define from_struct(key, struct_member) struct_member.FUNC_FROM_NAME(obj[key])
</span><span class="cp">#define END_FROM_JSON }
</span></code></pre></div><p>基本使用如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="k">struct</span> <span class="nc">Base</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">pp</span><span class="p">;</span>
    <span class="n">string</span> <span class="n">qq</span><span class="p">;</span>

    <span class="n">START_FROM_JSON</span> <span class="c1">//生成反序列化相关的方法
</span><span class="c1"></span>        <span class="n">pp</span> <span class="o">=</span> <span class="n">from</span><span class="p">(</span><span class="s">&#34;pp&#34;</span><span class="p">,</span> <span class="kt">int</span><span class="p">);</span>
        <span class="n">qq</span> <span class="o">=</span> <span class="n">from</span><span class="p">(</span><span class="s">&#34;qq&#34;</span><span class="p">,</span> <span class="n">string</span><span class="p">);</span>
    <span class="n">END_FROM_JSON</span>

    <span class="n">START_TO_JSON</span> <span class="c1">//生成序列化相关的代码
</span><span class="c1"></span>        <span class="n">to</span><span class="p">(</span><span class="s">&#34;pp&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">pp</span><span class="p">;</span>
        <span class="n">to</span><span class="p">(</span><span class="s">&#34;qq&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">qq</span><span class="p">;</span>
    <span class="n">END_TO_JSON</span>
<span class="p">};</span>

<span class="k">struct</span> <span class="nc">Mytest</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">id</span><span class="p">;</span>
    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span><span class="p">;</span>
    <span class="n">Base</span> <span class="n">q</span><span class="p">;</span>

    <span class="n">START_TO_JSON</span>	<span class="c1">//序列化相关代码
</span><span class="c1"></span>        <span class="n">to_struct</span><span class="p">(</span><span class="s">&#34;base&#34;</span><span class="p">,</span> <span class="n">q</span><span class="p">);</span>
        <span class="n">to</span><span class="p">(</span><span class="s">&#34;id&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">id</span><span class="p">;</span>
        <span class="n">to</span><span class="p">(</span><span class="s">&#34;name&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">name</span><span class="p">;</span>
    <span class="n">END_TO_JSON</span>

    <span class="n">START_FROM_JSON</span> <span class="c1">//反序列化相关代码
</span><span class="c1"></span>        <span class="n">id</span> <span class="o">=</span> <span class="n">from</span><span class="p">(</span><span class="s">&#34;id&#34;</span><span class="p">,</span> <span class="kt">int</span><span class="p">);</span>
        <span class="n">name</span> <span class="o">=</span> <span class="n">from</span><span class="p">(</span><span class="s">&#34;name&#34;</span><span class="p">,</span> <span class="n">string</span><span class="p">);</span>
        <span class="n">from_struct</span><span class="p">(</span><span class="s">&#34;base&#34;</span><span class="p">,</span> <span class="n">q</span><span class="p">);</span>
    <span class="n">END_FROM_JSON</span>
<span class="p">};</span>
</code></pre></div><p>实际上上面代码等效于下面的代码，以Base类为例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="k">struct</span> <span class="nc">Base</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">pp</span><span class="p">;</span>
    <span class="n">string</span> <span class="n">qq</span><span class="p">;</span>

    <span class="kt">void</span> <span class="nf">_from_json</span><span class="p">(</span><span class="n">json</span><span class="o">::</span><span class="n">JObject</span><span class="o">&amp;</span> <span class="n">obj</span><span class="p">){</span> <span class="c1">//反序列化
</span><span class="c1"></span>        <span class="n">pp</span> <span class="o">=</span> <span class="n">obj</span><span class="p">.</span><span class="n">Value</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">();</span>
        <span class="n">qq</span> <span class="o">=</span> <span class="n">obj</span><span class="p">.</span><span class="n">Value</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span><span class="p">();</span>
    <span class="p">}</span>
    
    <span class="kt">void</span> <span class="nf">_to_json</span><span class="p">(</span><span class="n">json</span><span class="o">::</span><span class="n">JObject</span><span class="o">&amp;</span> <span class="n">obj</span><span class="p">){</span><span class="c1">//序列化代码
</span><span class="c1"></span>        <span class="n">obj</span><span class="p">[</span><span class="s">&#34;pp&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">pp</span><span class="p">;</span>
        <span class="n">obj</span><span class="p">[</span><span class="s">&#34;qq&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">qq</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></div><h2 id="简单使用">简单使用</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="cp">#include</span><span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&#34;JObject.h&#34;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&#34;Parser.h&#34;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&#34;../benchmark/Timer.hpp&#34;</span><span class="cp">
</span><span class="cp"></span>
<span class="k">using</span> <span class="k">namespace</span> <span class="n">json</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Base</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">pp</span><span class="p">;</span>
    <span class="n">string</span> <span class="n">qq</span><span class="p">;</span>

    <span class="n">START_FROM_JSON</span>
        <span class="n">pp</span> <span class="o">=</span> <span class="n">from</span><span class="p">(</span><span class="s">&#34;pp&#34;</span><span class="p">,</span> <span class="kt">int</span><span class="p">);</span>
        <span class="n">qq</span> <span class="o">=</span> <span class="n">from</span><span class="p">(</span><span class="s">&#34;qq&#34;</span><span class="p">,</span> <span class="n">string</span><span class="p">);</span>
    <span class="n">END_FROM_JSON</span>

    <span class="n">START_TO_JSON</span>
        <span class="nf">to</span><span class="p">(</span><span class="s">&#34;pp&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">pp</span><span class="p">;</span>
        <span class="n">to</span><span class="p">(</span><span class="s">&#34;qq&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">qq</span><span class="p">;</span>
    <span class="n">END_TO_JSON</span>
<span class="p">};</span>

<span class="k">struct</span> <span class="nc">Mytest</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">id</span><span class="p">;</span>
    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span><span class="p">;</span>
    <span class="n">Base</span> <span class="n">q</span><span class="p">;</span>

    <span class="n">START_TO_JSON</span>
        <span class="nf">to_struct</span><span class="p">(</span><span class="s">&#34;base&#34;</span><span class="p">,</span> <span class="n">q</span><span class="p">);</span>
        <span class="n">to</span><span class="p">(</span><span class="s">&#34;id&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">id</span><span class="p">;</span>
        <span class="n">to</span><span class="p">(</span><span class="s">&#34;name&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">name</span><span class="p">;</span>
    <span class="n">END_TO_JSON</span>

    <span class="n">START_FROM_JSON</span>
        <span class="n">id</span> <span class="o">=</span> <span class="n">from</span><span class="p">(</span><span class="s">&#34;id&#34;</span><span class="p">,</span> <span class="kt">int</span><span class="p">);</span>
        <span class="n">name</span> <span class="o">=</span> <span class="n">from</span><span class="p">(</span><span class="s">&#34;name&#34;</span><span class="p">,</span> <span class="n">string</span><span class="p">);</span>
        <span class="n">from_struct</span><span class="p">(</span><span class="s">&#34;base&#34;</span><span class="p">,</span> <span class="n">q</span><span class="p">);</span>
    <span class="n">END_FROM_JSON</span>
<span class="p">};</span>

<span class="kt">void</span> <span class="nf">test_class_serialization</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">Mytest</span> <span class="n">test</span><span class="p">{.</span><span class="n">id</span><span class="o">=</span><span class="mi">32</span><span class="p">,</span> <span class="p">.</span><span class="n">name</span><span class="o">=</span><span class="s">&#34;fda&#34;</span><span class="p">};</span>
    <span class="k">auto</span> <span class="n">item</span> <span class="o">=</span> <span class="n">Parser</span><span class="o">::</span><span class="n">FromJson</span><span class="o">&lt;</span><span class="n">Mytest</span><span class="o">&gt;</span><span class="p">(</span><span class="n">R</span><span class="s">&#34;({&#34;</span><span class="n">base</span><span class="s">&#34;:{&#34;</span><span class="n">pp</span><span class="s">&#34;:0,&#34;</span><span class="n">qq</span><span class="s">&#34;:&#34;&#34;},&#34;</span><span class="n">id</span><span class="s">&#34;:32,&#34;</span><span class="n">name</span><span class="s">&#34;:&#34;</span><span class="n">fda</span><span class="s">&#34;} )&#34;</span><span class="p">);</span> <span class="c1">//serialization
</span><span class="c1"></span>    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">Parser</span><span class="o">::</span><span class="n">ToJSON</span><span class="p">(</span><span class="n">item</span><span class="p">);</span> <span class="c1">//deserialization
</span><span class="c1"></span><span class="p">}</span>

<span class="kt">void</span> <span class="nf">test_string_parser</span><span class="p">()</span>
<span class="p">{</span>
    <span class="p">{</span>
        <span class="n">Timer</span> <span class="n">t</span><span class="p">;</span>
        <span class="n">std</span><span class="o">::</span><span class="n">ifstream</span> <span class="n">fin</span><span class="p">(</span><span class="s">&#34;../../test_source/test.json&#34;</span><span class="p">);</span>
        <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">text</span><span class="p">((</span><span class="n">std</span><span class="o">::</span><span class="n">istreambuf_iterator</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">(</span><span class="n">fin</span><span class="p">)),</span> <span class="n">std</span><span class="o">::</span><span class="n">istreambuf_iterator</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">());</span>
        <span class="n">json</span><span class="o">::</span><span class="n">Parser</span> <span class="n">p</span><span class="p">;</span>
        <span class="n">p</span><span class="p">.</span><span class="n">init</span><span class="p">(</span><span class="n">text</span><span class="p">);</span>
        <span class="k">auto</span> <span class="n">q</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">parse</span><span class="p">();</span>
        <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span> <span class="n">fout</span><span class="p">(</span><span class="s">&#34;../../test_source/test_out.json&#34;</span><span class="p">);</span>
        <span class="n">fout</span> <span class="o">&lt;&lt;</span> <span class="n">q</span><span class="p">.</span><span class="n">to_string</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
   <span class="n">test_class_serialization</span><span class="p">();</span>
   <span class="n">test_string_parser</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div><div class="post-footer" id="post-footer">
    <div class="post-info"><div class="post-info-tag"><span><a href="/tags/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0/">JSON解析器实现</a>
                </span></div><div class="post-info-line"><div class="post-info-mod">
                <span>更新于 2022-07-27</span>
            </div><div class="post-info-mod"></div>
        </div><div class="post-info-share">
            <span><a href="javascript:void(0);" title="分享到 Twitter" data-sharer="twitter" data-url="https://acking-you.github.io/posts/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0/" data-title="JSON解析器实现" data-hashtags="JSON解析器实现"><i class="fab fa-twitter fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Facebook" data-sharer="facebook" data-url="https://acking-you.github.io/posts/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0/" data-hashtag="JSON解析器实现"><i class="fab fa-facebook-square fa-fw"></i></a><a href="javascript:void(0);" title="分享到 WhatsApp" data-sharer="whatsapp" data-url="https://acking-you.github.io/posts/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0/" data-title="JSON解析器实现" data-web><i class="fab fa-whatsapp fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Line" data-sharer="line" data-url="https://acking-you.github.io/posts/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0/" data-title="JSON解析器实现"><i class="fab fa-line fa-fw"></i></a><a href="javascript:void(0);" title="分享到 微博" data-sharer="weibo" data-url="https://acking-you.github.io/posts/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0/" data-title="JSON解析器实现" data-image="https://img-blog.csdnimg.cn/img_convert/c2804a2e21ea79a0b060126b82a9145c.png#pic_center"><i class="fab fa-weibo fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Myspace" data-sharer="myspace" data-url="https://acking-you.github.io/posts/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0/" data-title="JSON解析器实现" data-description="JSON解析器实现"><i data-svg-src="/lib/simple-icons/icons/myspace.min.svg"></i></a><a href="javascript:void(0);" title="分享到 Blogger" data-sharer="blogger" data-url="https://acking-you.github.io/posts/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0/" data-title="JSON解析器实现" data-description="JSON解析器实现"><i class="fab fa-blogger fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Evernote" data-sharer="evernote" data-url="https://acking-you.github.io/posts/json%E8%A7%A3%E6%9E%90%E5%99%A8%E5%AE%9E%E7%8E%B0/" data-title="JSON解析器实现"><i class="fab fa-evernote fa-fw"></i></a></span>
        </div></div><div class="post-nav"><a href="/posts/logger%E6%97%A5%E5%BF%97%E5%BA%93%E7%9A%84%E5%AE%9E%E7%8E%B0/" class="prev" rel="prev" title="Logger日志库的实现"><i class="fas fa-angle-left fa-fw"></i>Previous Post</a>
            <a href="/posts/c&#43;&#43;%E9%9D%A2%E8%AF%95%E4%B8%80%E6%9D%A1%E8%B7%AF/" class="next" rel="next" title="C&#43;&#43;面试面试一条龙">Next Post<i class="fas fa-angle-right fa-fw"></i></a></div></div>
</div></article></div>
            </main>
            <footer class="footer"><div class="footer-container"><div class="footer-line">由 <a href="https://gohugo.io/" target="_blank" rel="noopener noreffer" title="Hugo 0.86.0">Hugo</a> 强力驱动 | 主题 - <a href="https://github.com/khusika/FeelIt" target="_blank" rel="noopener noreffer" title="FeelIt 1.0.1"><i class="fas fa-hand-holding-heart fa-fw"></i> FeelIt</a>
        </div><div class="footer-line" itemscope itemtype="http://schema.org/CreativeWork"><i class="far fa-copyright fa-fw"></i><span itemprop="copyrightYear">2023</span><span class="author" itemprop="copyrightHolder">&nbsp;<a href="/"></a></span></div>
</div>
</footer>
        </div>

        <div id="fixed-buttons"><a href="#" id="back-to-top" class="fixed-button" title="回到顶部">
                <i class="fas fa-chevron-up fa-fw"></i>
            </a></div><link rel="stylesheet" href="/lib/fontawesome-free/all.min.css"><link rel="stylesheet" href="/lib/animate/animate.min.css"><link rel="stylesheet" href="/lib/katex/katex.min.css"><link rel="stylesheet" href="/lib/katex/copy-tex.min.css"><script src="/lib/autocomplete/autocomplete.min.js"></script><script src="/lib/lunr/lunr.min.js"></script><script src="/lib/lunr/lunr.stemmer.support.min.js"></script><script src="/lib/lunr/lunr.zh.min.js"></script><script src="/lib/lazysizes/lazysizes.min.js"></script><script src="/lib/clipboard/clipboard.min.js"></script><script src="/lib/sharer/sharer.min.js"></script><script src="/lib/katex/katex.min.js"></script><script src="/lib/katex/auto-render.min.js"></script><script src="/lib/katex/copy-tex.min.js"></script><script src="/lib/katex/mhchem.min.js"></script><script>window.config={"code":{"copyTitle":"复制到剪贴板","maxShownLines":200},"comment":{},"math":{"delimiters":[{"display":true,"left":"$$","right":"$$"},{"display":true,"left":"\\[","right":"\\]"},{"display":false,"left":"$","right":"$"},{"display":false,"left":"\\(","right":"\\)"}],"strict":false},"search":{"highlightTag":"em","lunrIndexURL":"/index.json","lunrLanguageCode":"zh","lunrSegmentitURL":"/lib/lunr/lunr.segmentit.js","maxResultLength":100,"noResultsFound":"没有找到结果","snippetLength":50,"type":"lunr"}};</script><script src="/js/theme.min.js"></script></body></html>
